<!-- 视频观看人脸对比 组件 -->

<template>
	<view>
		
		<!-- 人脸对比呈现组件外层 -->
		<view class="face-than-comp-shell">
			
			<!-- 圆角文字信息框容器 -->
			<view v-if="state.draw" class="face-than-block-content">
				<!-- 扫脸提示图标 -->
				<image class="face-than-img-face" :src="state.list[state.index].img"></image>
				<!-- 状态描述文字 -->
				<text :style="{'color':state.list[state.index].color}"
				class="face-than-font-state">{{state.list[state.index].text}}</text>
				<!-- 倒计时描述数值 -->
				<text 
					v-if="state.list[state.index].time"
					:style="{'color':state.list[state.index].color,'margin-left':'10rpx'}"
					class="face-than-font-state">{{state.list[state.index].time+'s'}}</text>
				<!-- 动态圆点 -->
				<view v-if="state.index==1" class="face-than-arc-animt"></view>
			</view>
			
			<!-- 成像摄像头容器 -->
			<view v-if="detection.isEnable" class="face-than-block-camera">
				
				<!-- 自定义摄像头 组件 -->
				<camera-embed ref="myCameraDjy" :size="[90,160]" position="front"></camera-embed>
				
				<!-- 帧数据图片 -->
				<!-- <view class="face-than-block-thanimg">
					<image style="width:90rpx; height:160rpx; background-color:#C1AE8D;" :src="src_img"></image>
				</view> -->
				
			</view>
			
		</view>
	</view>
</template>


<script>
	// 接口请求文件引入
	import request from '@/pagesB/common/js/request/userInfo.js'; // 用户处理
	import request_course from '@/pagesB/common/js/request/course.js'; // 课程处理
	import { base64ToPath } from '@/pagesB/components/img-tools/index.js';
	
	/**
	 * 视频观看人脸对比组件
	 * @description 视频观看人脸对比组件，杜先生开发
	 * @property {String} tag 组件标识，默认：face-than
	 * @property {Boolean} enable 是否启用，默认：false
	 * @property {String,Number} courseid 课程id
	 * @property {String,Number} jieid 节ID
	 * @property {String,Number} progress 当前视频播放进度
	 */
	export default {
		name: 'face-than',
		// 组件需要获取数据
		props: {
			"tag": { type: String, default: 'face-than' },
			"enable": { type: Boolean, default: false },
			"courseid": { type: [String,Number], default: 0 },
			"jieid": { type: [String,Number], default: 0 },
			"progress": { type: [String,Number], default: 0 },
		},
		
		// 页面数据
		data() {
			return {
				// 
				faceImgSec: '',
				// 显示图片
				src_img: '',
				
				// 要检测的进度标记点信息
				detection: {
					// 是否开启对比检测功能
					isEnable: false,
					// 是否正处于检测处理中
					isDealing: false,
					// “人脸对比”接口是否空闲
					canRequest: true,
					// 相似度通过分数
					score: 80,
					// 当前处于的下标位置
					index: 0,
					// 进度标记点列表
					sign: ['50'],
					// 标记点检测结果
					results: [
						{ isDeal: false, isSuc: false, base64: '', file: '', remark: '' }
					],
				},
				
				// 定时器变量
				timer: {
					willdo: null, // 即将核对提示倒计时 (计时器)
					outTime: null, // 人脸对比超时处理 (定时器)
					resultShow: null, // 对比结果显示弹框倒计时 (定时器)
				},
				
				// 状态显示信息
				state: {
					// 是否渲染组件
					draw: false,
					// 当前显示状态下标
					index: 0,
					// 状态信息列表
					list: [
						{ color: '#FFFFFF', text: '即将进行学员身份核对', time: 0, img: '/static/img/face/face-normol.png' },
						{ color: '#F3C428', text: '学员身份核对中，请注视屏幕', img: '/static/img/face/face-doing.png' },
						{ color: '#24C819', text: '学员身份核对成功', img: '/static/img/face/face-success.png' },
						{ color: '#FF0000', text: '学员身份核对失败', img: '/static/img/face/face-fail.png' }
					],
				},
				
				// 用户确定框
				toastUserClick: {
					index: 0,
					list: [
						{
							type: 2,
							content: '学员身份信息核对失败', // 弹框标题
							details: "为了保障学员的学习情况，现将对学习过程实施管控，还望理解", // 详情
							btnone: '我知道了，继续观看', // 主要按钮文字
							btntwo: '', // 次级按钮文字
							openclose: false, // 是否开启关闭按钮
						},
						{
							type: 3,
							content: '学员身份信息核对失败 (实时核对环节正在开发中...)', // 弹框标题
							details: "为了保障学员的学习情况，现将对学习过程实施管控，还望理解", // 详情
							btnone: '开始核对', // 主要按钮文字
							btntwo: '暂不核对', // 次级按钮文字
							openclose: false, // 是否开启关闭按钮
						}
					],
				},
			}
		},
		
		// 创建完成
		created() {
			// 是否获取到了摄像头权限
			uni.authorize({
				scope: 'scope.camera',
				fail: () => {
					// 如果未开启权限，那么关闭检测功能
					this.detection.isEnable = false;
				},
				success: () => {
					// 如果有权限，那么开启检测功能
					this.detection.isEnable = true;
				}
			});
		},
		
		// 数据监听
		watch: {
			// 播放进度 变化
			progress: {
				handler(newValue, oldValue) {
					// 开启了检测 && 数值有效才执行 && 当前未在“处理中”状态
					if (this.enable==true && this.detection.isEnable==true && newValue>=0 && this.detection.isDealing==false)
					{
						// 当前进度在 “要检测的进度点列表” 中的位置
						// var index_progress = this.detection.sign.indexOf(newValue.toString());
						var index_progress = 0;
						// 存在此位置，并且该位置还未检测过
						if (Number(newValue)>=50 && Number(newValue)<60 && this.detection.results[index_progress].isDeal==false)
						{
							// 标记为“正在处理”
							this.detection.isDealing = true;
							// 监测点的下标位置 赋值
							this.detection.index = index_progress;
							// 进行 “即将核对”操作步骤
							this.willSteps(()=>{
								// 进行 “正在核对”操作步骤
								this.doingSteps();
							});
						}
					}
				},
				immediate: true
			},
		},
		
		// 组件销毁
		beforeDestroy() {
			// 即将核对提示倒计时
			if (this.timer.willdo) { clearInterval(this.timer.willdo); }
			// 人脸对比超时处理
			if (this.timer.outTime) { clearTimeout(this.timer.outTime); }
			// 对比结果显示弹框倒计时
			if (this.timer.resultShow) { clearTimeout(this.timer.resultShow); }
		},
		
		// 事件
		methods: {
			
			// ======================================== 父级$refs事件
			// 初始化组件数据信息
			initData() {
				// 注销所有计/定时器
				if (this.timer.willdo) { clearInterval(this.timer.willdo); }
				if (this.timer.outTime) { clearTimeout(this.timer.outTime); }
				if (this.timer.resultShow) { clearTimeout(this.timer.resultShow); }
				
				// 关闭摄像头
				if (this.$refs.myCameraDjy) { this.$refs.myCameraDjy.close(); }
				// 隐藏组件状态步骤图标
				this.state.draw = false;
				
				// 标记为“未在处理”
				this.detection.isDealing = false;
				// 初始化：要检测的进度标记点信息
				this.detection.index = 0;
				// 初始化：标记点检测结果
				for (let i = 0; i < this.detection.results.length; i++)
				{
					// 将每一项初始化
					this.detection.results[i] = {
						isDeal: false,
						isSuc: false,
						base64: '',
						file: '',
						remark: '',
					};
				}
				
			},
			
			
			// ======================================== 数据处理
			// “即将核对”操作步骤，参数： callback-执行完毕
			willSteps(callback) {
				// 进行 状态0：“即将进行” 提醒
				this.state.index = 0;
				// 进行“即将核对”倒计时提醒
				this.state.list[0].time = 3;
				// 渲染组件
				this.state.draw = true;
				// 执行：打开摄像头方法
				if (this.$refs.myCameraDjy) { this.$refs.myCameraDjy.open(); }
				
				// 使用计时器倒计时
				if (this.timer.willdo) { clearInterval(this.timer.willdo); }
				this.timer.willdo = setInterval(()=>{
					// 时间 -1
					this.state.list[0].time = this.state.list[0].time - 1;
					// 如果时间走完
					if (this.state.list[0].time <= 0){
						// 清除计时器
						if (this.timer.willdo) { clearInterval(this.timer.willdo); }
						// 销毁组件
						this.state.draw = false;
						// 如果打开摄像头成功 - 执行回调
						if (callback) { callback(); }
					}
				}, 1000);
				
			},
			// “正在核对”操作步骤
			doingSteps() {
				
				// 进行 状态1：“进行中” 提醒
				this.state.index = 1;
				// 渲染组件
				this.state.draw = true;
				// 标记为“允许请求”
				this.detection.canRequest = true;
				
				// 人脸对比超时定时器
				if (this.timer.outTime) { clearTimeout(this.timer.outTime); }
				this.timer.outTime = setTimeout(()=>{ // 8s超时
					// 关闭摄像头
					if (this.$refs.myCameraDjy) { this.$refs.myCameraDjy.close(); }
					// 如果记录数据里面为空
					if (this.detection.results[this.detection.index].isDeal != true)
					{
						// 将错误原因放入到 标记点检测结果
						this.detection.results[this.detection.index].remark = '人脸对比超时';
						// 标记当前项为“失败”
						this.detection.results[this.detection.index].isSuc = false;
						// 标记当前项为“已处理”
						this.detection.results[this.detection.index].isDeal = true;
					}
					// 销毁组件
					this.state.draw = false;
					// “核对失败”操作步骤
					this.failSteps();
				}, 8000);
				
				// 获取实时帧数据
				this.$refs.myCameraDjy.onCameraFrame((objD)=>{
					this.faceImgSec = objD.faceSrc
					// this.src_img = objD.src;
					// 如果允许进行接口请求
					if (this.detection.canRequest)
					{
						// 标记为“不允许请求”
						this.detection.canRequest = false;
						// 发起 人脸比对 接口请求
						this.userFaceThanReq(objD, ()=>{ // 如果人脸对比成功
							// 注销 人脸对比超时定时器
							if (this.timer.outTime) { clearTimeout(this.timer.outTime); }
							// 关闭摄像头
							if (this.$refs.myCameraDjy) { this.$refs.myCameraDjy.close(); }
							// 销毁组件
							this.state.draw = false;
							// “核对成功”操作步骤
							this.successSteps();
						});
					}
				});
				
			},
			// “核对成功”操作步骤
			successSteps() {
				
				// 进行 状态2：“对比成功” 提醒
				this.state.index = 2;
				// 渲染组件
				this.state.draw = true;
				
				// 如果到达最后一个项了，检测结果发送
				if (this.detection.index+1 >= this.detection.sign.length) { this.faceThanHistoryReq(); }
				
				// 延时关闭提醒
				if (this.timer.resultShow) { clearTimeout(this.timer.resultShow); }
				this.timer.resultShow = setTimeout(()=>{
					// 标记为“未在处理”
					this.detection.isDealing = false;
					// 销毁自身组件
					this.state.draw = false;
				}, 2000);
				
			},
			// “核对失败”操作步骤
			failSteps() {
				
				// 进行 状态3：“对比失败” 提醒
				this.state.index = 3;
				// 渲染组件
				this.state.draw = true;
				
				/* // 如果当前验证已经确定未通过了
				if (this.isReachStandard() == false)
				{
					// 根据后端配置的“失败行为”执行：
					// 1. 不处理
					// 2. 暂停播放，弹框等待用户确定后继续
					if (this.detection.failAction == 2)
					{
						// 弹出确定框
						this.toastUserClick.index = 0;
						this.$refs.myToastUserClick.open();
						// "@"回调事件：验证未通过
						this.$emit('passnot');
					}
					// 3. 暂停播放，弹框引导用户进行人脸识别，识别通过才可继续
					else if (this.detection.failAction == 3)
					{
						// 弹出实时核对框
						this.toastUserClick.index = 1;
						this.$refs.myToastUserClick.open();
						// "@"回调事件：验证未通过
						this.$emit('passnot');
					}
					
					// 检测结果发送
					this.videoDetectionResultsReq();
				} */
				// 如果到达最后一个项了，检测结果发送
				if (this.detection.index+1 >= this.detection.sign.length) { this.faceThanHistoryReq(); }
				
				// 延时关闭提醒
				if (this.timer.resultShow) { clearTimeout(this.timer.resultShow); }
				this.timer.resultShow = setTimeout(()=>{
					// 标记为“未在处理”
					this.detection.isDealing = false;
					// 销毁自身组件
					this.state.draw = false;
				}, 2000);
			
			},
			
			
			// ======================================== 接口请求
			// 人脸比对，参数： objD-摄像头组件返回数据  callback-成功回调
			userFaceThanReq(objD, callback) {
				// 当前处理节点下标
				var index_progress = Number(this.detection.index);
				// 调用人脸对比接口
							request.userFaceThan({
								data: {
									image: objD.data, // 图片信息
									score: this.detection.score, // 相似度通过分数
								},
								fail: (res) => {
									// 失败图片保存
									this.detection.results[index_progress].base64 = objD.src.split(',')[1];
									// 失败原因记录
									this.detection.results[index_progress].remark = res.error_code==0 ? 'FAIL: '+res.result.score : res.error_code+': '+res.error_msg;
									// 标记为“对比失败”
									this.detection.results[index_progress].isSuc = false;
									// 标记为“已经检测过”
									this.detection.results[index_progress].isDeal = true;
									// 标记为“允许请求”
									this.detection.canRequest = true;
								},
								success: (res) => {
									// console.log('===== 人脸比对成功：', res);
									// 成功图片保存
									this.detection.results[index_progress].base64 = objD.src.split(',')[1];
									// 成功原因记录
									this.detection.results[index_progress].remark = res.error_msg + ': ' + res.result.score;
									// 标记为“对比成功”
									this.detection.results[index_progress].isSuc = true;
									// 标记为“已经检测过”
									this.detection.results[index_progress].isDeal = true;
									// 成功回调
									if (callback) { callback(); }
								}
							});
			},
			// 添加课程观看人脸对比记录
			faceThanHistoryReq() {
				// 2、上传图片
				wx.saveFile({
					tempFilePath: this.faceImgSec,
					success: ({ savedFilePath: file }) => {
						uni.uploadFile({
						  url: 'https://agapi.cqjjb.cn/api/aq_attach/v2/upload/file',
						  filePath: file,
						  name: 'file',
						  success: res => {
							const { data } = res;
							const jsonData = JSON.parse(data);
							if([1, '1'].includes(jsonData.code)) {
								const { data: resData } =  jsonData;
								// 修改用户真实照片数据
								request_course.faceThanHistory({
									data: {
										teach_course_info_id: this.courseid, // 课程id
										teach_chapter_id: this.jieid, // 小节ID
										status: this.detection.results[0].isSuc==true ? 1 : 2, // 是否通过：1-通过 2-未通过
										msg: this.detection.results[0].remark, // 备注信息
										img: resData.attach_id 
									},
								});
							}
						  },
						})
					},
					fail: err => console.log("失败：", err)
				})
				
			},
			
		},
		
	}
</script>


<style scoped>
	/* 组件外层 */
	.face-than-comp-shell{ height: 60rpx; position: relative; background-color: rgba(0,0,0,0.5); border-radius: 12rpx; overflow: hidden; }
	
	/* 文字信息框 */
	.face-than-block-content{ height: 60rpx; padding-left: 20rpx; padding-right: 20rpx; display: flex; flex-direction: row; justify-content: flex-start; align-items: center; }
	/* 扫脸提示图标 */
	.face-than-img-face{ width: 40rpx; height: 40rpx; margin-right: 20rpx; }
	/* 状态描述文字 */
	.face-than-font-state{ font-size: 24rpx; line-height: 40rpx; color: #FFFFFF; }
	/* 动态圆点 */
	.face-than-arc-animt{
		width: 14rpx; height: 14rpx;
		margin-left: 24rpx;
		border-radius: 7rpx;
		animation-name: _animt_face_than_arc;
		animation-duration: 1600ms;
		animation-timing-function: linear;
		animation-fill-mode: both;
		animation-iteration-count: infinite;
	}
	/* 圆点css3动画样式 */
	@keyframes _animt_face_than_arc{
	    0% { background-color: #666666; }
		50% { background-color: #FF0000; }
	    100% { background-color: #666666; }
	}
	
	/* 摄像头容器 */
	.face-than-block-camera{ position: absolute; left: 0; top: 80rpx; display: flex; flex-direction: row; justify-content: flex-start; align-items: center; }
	/* 图片容器 */
	.face-than-block-thanimg{ width: 90rpx; height: 160rpx; margin-left: 20rpx; }
</style>